<?php
error_reporting(E_ALL);

require_once '../Controller/Functions.php';
require_once '../Model/model_require_once.php';
require_once '../Constants.php';

set_time_limit ( 300 );

$wss_path = dirname(__FILE__) . "/../../" . CUSTOM_STUBS_DIR . "/web_service_security.php";

//include the custom directory in case there are custom db elements
includeDir(dirname(__FILE__) . "/../../" . CUSTOM_STUBS_DIR . "/");

if (file_exists ( $wss_path ))
require_once $wss_path;
//TODO: add security for script access to MADAL
else {
	echo "ERROR: web service security not found at " . $wss_path;
}

/* @var $wss WebServiceSecurity */
$wss = new WebServiceSecurity ( );

$parameters = array ();
if (count ( $_GET ) > 0) {
	$parameters = $_GET;
} else if (count ( $_POST ) > 0) {
	$parameters = $_POST;
} else {
	//print the help file
	require_once "web_service_help.php";
	return;
}

//check if they've passed in the basic parameters
if (isset ( $parameters ["model"] ) && isset ( $parameters ["method"] ) && isset ( $parameters ['encoding'] )) {
	//if they have, check security
	if (! $wss->checkGeneralSecurity ( $parameters )) {
		die ( "Security check failed on General Security Check. " . $wss->getComments () );
	}
}

//get model class
if (isset ( $parameters ['model'] )) {
	$model = $parameters ['model'];
} else {
	echo "Please provide model parameter, submit with no parameters for 'help'.<br>";
}

//get method
if (isset ( $parameters ['method'] )) {
	$method = $parameters ['method'];
} else {
	echo "Please provide method parameter, submit with no parameters for 'help'.<br>";
}

//check if the method starts with insertNew, then we don't need a primary key
if(StartsWith("insertNew", $parameters ['method'])){
	$class_instance = new $model ( );
	$properties_list = explode(", ", getClassProperties($model));
	foreach($properties_list as $prop){
		if(isset ( $parameters [$prop] ) && $parameters [$prop] != 'undefined' && $prop != "username" && $prop != "password"){
			$class_instance->$prop = $parameters [$prop];
		}
		else if(isset ($parameters [$prop]) && ($prop == "username" || $prop == "password")){
			if(isset($parameters ["method_".$prop])){
				$class_instance->$prop = $parameters ["method_".$prop];
			}
		}
	}
	try{
		echo json_encode($class_instance->insertMe());
		return true;
	}
	catch(Exception $e){
		echo json_encode($e);
		return false;
	}
}
//get primary key
else if (isset ( $parameters ['primary_key_value'] )) {
	$primary_key_value = $parameters ['primary_key_value'];
}

//get encoding
if (isset ( $parameters ['encoding'] )) {
	$class_vars = get_class_vars ( $model );

	/* @var $methodReflector ReflectionMethod */
	if(method_exists ( $model, $method ) ){
		$methodReflector = new ReflectionMethod($model, $method);
		if($methodReflector->isStatic())
		{
			//turn our list of parameters passed from the url, and method signature parameters into an argument list
			$args = constructArgList($methodReflector, $parameters);

			//call the method statically
			$result = call_user_func_array ($model . "::" .$method, $args);
		}
		else{
			$primary_key_field = $class_vars ['primary_key_field'];
			$constructor = "constructFrom_$primary_key_field";
			$class_instance = new $model ( );
			if(isset($primary_key_value)){
				//construct the class
				try{
					$target = $class_instance->$constructor ( $primary_key_value );
				}
				catch(Exception $e){
					die(json_encode($e));
				}
			}
			else if(!$reflectionMethod->isStatic()){
				die("Please provide primary_key_value parameter, submit with no parameters for 'help'.<br>");
			}

			if (! $wss->checkModelSecurity ( $target )) {
				die ( "Security check failed on Model Security Check. " . $wss->getComments () );
			}

			//turn our list of parameters passed from the url, and method signature parameters into an argument list
			$args = constructArgList($methodReflector, $parameters);
			
			if (count($args) > 0) {
				//get result and pass args
				$result = call_user_func_array ( array ($target, $method ), $args );
			} else {
				//get result no args
				$result = $target->$method ();
			}
		}
		//encode result
		if ($parameters ['encoding'] == "xml") {
			header ( "Content-Type: text/xml" );
			echo wsSerialize ( $result );
		} else if ($parameters ['encoding'] == "json") {
			header ( "Content-Type: application/json" );
			echo json_encode ( $result );
		}
	}
	else{
		echo "Method {$model}->{$method} does not exist.";
	}

} else {
	echo "Please provide encoding parameter as 'xml' or 'json', submit with no parameters for 'help'. <br>";
}

/**
 * Turn our list of parameters passed from the url, and method signature parameters into an argument list
 * @param array $url_parameters
 * @param array $method_parameters
 */
function constructArgList($methodReflector, $url_parameters){
	/* @var $parameterReflector ReflectionParameter */
	$method_parameters = $methodReflector->getParameters();

	$args = array ();
	//need to check for parameters whose name is 'username' or 'password', these will get confused with the security username and password.
	//if a parameter is 'username' or 'password', look for method_username and method_password.
	foreach ( $method_parameters as $parameterReflector ) {
		$arg = $parameterReflector->getName();

		if (isset ( $url_parameters [$arg] ) && $arg != "username" && $arg != "password"){
			array_push ( $args, $url_parameters [$arg] );
		}
		else if($arg == "username" || $arg == "password"){
			if(isset($url_parameters ["method_".$arg])){
				array_push ( $args, $url_parameters ["method_".$arg] );
			}
			else{
				die ("Parameter method_{$arg} must be provided to call {$methodReflector->getName()} <br>");
			}
		}
		else if(!$parameterReflector->isOptional()){
			die ("Parameter $arg must be provided to call {$methodReflector->getName()} <br>");
		}
	}

	return $args;
}

/**
 * Serializes an object
 *
 * @param mixed $object
 * @return string xml
 */
function wsSerialize($object) {
	if(class_exists("XML_Serializer")){
		// An array of serializer options
		$serializer_options = array (XML_SERIALIZER_OPTION_INDENT => '	', XML_SERIALIZER_OPTION_TYPEHINTS => TRUE, XML_SERIALIZER_OPTION_DEFAULT_TAG => 'array_item' );
		// create object
		$serializer = new XML_Serializer ( $serializer_options );
		$status = $serializer->serialize ( $object );
		if (PEAR::isError ( $status )) {
			throw new Exception ( $status->getMessage () );
		}

		return $serializer->getSerializedData ();
	}
	else{
		throw new Exception ( "<error>Your server does not include the XML/Serializer.php PEAR class. Please setup this PEAR extension on your server and regenerate your classes to make XML serialization available.</error>");
	}
}

/**
 * Includes all files in a specified directory
 * @param $dir_path The path of the directory to include
 */
function includeDir($dir_path){
	$dir_handle = @opendir($dir_path) or die("Unable to open $dir_path");

	$files = array();

	while ($file = readdir($dir_handle))
	{
		$files[] = "$file";
		if(is_file($dir_path . "$file")){
			include_once $dir_path . "$file";
		}
	} // end while loop
}
?>
